/*


  parameter int pBMAX = 12;



  logic                  gray_bit_mapper__iclk     ;
  logic                  gray_bit_mapper__ireset   ;
  logic                  gray_bit_mapper__iclkena  ;
  logic                  gray_bit_mapper__isop     ;
  logic                  gray_bit_mapper__ival     ;
  logic                  gray_bit_mapper__ieop     ;
  logic          [3 : 0] gray_bit_mapper__iqam     ;
  logic    [pBMAX-1 : 0] gray_bit_mapper__idat     ;
  logic                  gray_bit_mapper__osop     ;
  logic                  gray_bit_mapper__oval     ;
  logic                  gray_bit_mapper__oeop     ;
  logic          [3 : 0] gray_bit_mapper__oqam     ;
  logic  [pBMAX/2-1 : 0] gray_bit_mapper__odat_re  ;
  logic  [pBMAX/2-1 : 0] gray_bit_mapper__odat_im  ;



  gray_bit_mapper
  #(
    .pBMAX ( pBMAX )
  )
  gray_bit_mapper
  (
    .iclk    ( gray_bit_mapper__iclk    ) ,
    .ireset  ( gray_bit_mapper__ireset  ) ,
    .iclkena ( gray_bit_mapper__iclkena ) ,
    .isop    ( gray_bit_mapper__isop    ) ,
    .ival    ( gray_bit_mapper__ival    ) ,
    .ieop    ( gray_bit_mapper__ieop    ) ,
    .iqam    ( gray_bit_mapper__iqam    ) ,
    .idat    ( gray_bit_mapper__idat    ) ,
    .osop    ( gray_bit_mapper__osop    ) ,
    .oval    ( gray_bit_mapper__oval    ) ,
    .oeop    ( gray_bit_mapper__oeop    ) ,
    .oqam    ( gray_bit_mapper__oqam    ) ,
    .odat_re ( gray_bit_mapper__odat_re ) ,
    .odat_im ( gray_bit_mapper__odat_im )
  );


  assign gray_bit_mapper__iclk    = '0 ;
  assign gray_bit_mapper__ireset  = '0 ;
  assign gray_bit_mapper__iclkena = '0 ;
  assign gray_bit_mapper__isop    = '0 ;
  assign gray_bit_mapper__ival    = '0 ;
  assign gray_bit_mapper__ieop    = '0 ;
  assign gray_bit_mapper__iqam    = '0 ;
  assign gray_bit_mapper__idat    = '0 ;



*/

//
// Project       : FEC library
// Author        : Shekhalev Denis (des00)
// Workfile      : gray_bit_mapper.v
// Description   : gray bit mapper up to QAM4096
//

module gray_bit_mapper
#(
  parameter int pBMAX = 12  // <= 12. maximum number of bits per symbols, must be even (!!!)
)
(
  iclk    ,
  ireset  ,
  iclkena ,
  //
  isop    ,
  ival    ,
  ieop    ,
  iqam    ,
  idat    ,
  //
  osop    ,
  oval    ,
  oeop    ,
  oqam    ,
  odat_re ,
  odat_im
);

  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------

  input  logic                 iclk    ;
  input  logic                 ireset  ;
  input  logic                 iclkena ;
  //
  input  logic                 isop    ;
  input  logic                 ival    ;
  input  logic                 ieop    ;
  input  logic         [3 : 0] iqam    ;
  input  logic   [pBMAX-1 : 0] idat    ;
  //
  output logic                 osop    ;
  output logic                 oval    ;
  output logic                 oeop    ;
  output logic         [3 : 0] oqam    ;
  output logic [pBMAX/2-1 : 0] odat_re ;
  output logic [pBMAX/2-1 : 0] odat_im ;

  //------------------------------------------------------------------------------------------------------
  // bit conversion tables for not square modulations
  //------------------------------------------------------------------------------------------------------

  localparam int cDAT_W = pBMAX/2;

  //  8PSK mapper : a = cos(pi/8), b = cos(3*pi/8)
  //    000 (0) = -b - ai
  //    001 (1) = -a - bi
  //    011 (3) =  a - bi
  //    010 (2) =  b - ai
  //    110 (6) =  b + ai
  //    111 (7) =  a + bi
  //    101 (5) = -a + bi
  //    100 (4) = -b + ai

  localparam logic [3 : 0] cQAM8_TAB [0 : 7] = '{
    4'b00_01, // 0
    4'b01_00, // 1
    4'b00_10, // 2
    4'b01_11, // 3
    4'b11_01, // 4
    4'b10_00, // 5
    4'b11_10, // 6
    4'b10_11  // 7
  };

  localparam logic [5 : 0] cQAM32_TAB  [0 : 31]   = '{
    18, 10, 26, 34, 17, 9, 25, 33, 19, 11, 27, 35, 20, 12, 28, 36, 8, 2, 32, 42, 16, 1, 24, 41, 13, 3, 37, 43, 21, 4, 29, 44
  };

  localparam logic [7 : 0] cQAM128_TAB [0 : 127]  = '{
      39,   55,   38,   54,   87,   71,   86,   70,   40,   56,   41,   57,   88,   72,   89,   73,   151,  135,  150,  134,  103,  119,  102,  118,  152,  136,  153,  137,  104,  120,  105,  121,
      36,   52,   37,   53,   84,   68,   85,   69,   35,   51,   34,   50,   83,   67,   82,   66,   148,  132,  149,  133,  100,  116,  101,  117,  147,  131,  146,  130,  99,   115,  98,   114,
      23,   7,    22,   6,    8,    9,    43,   59,   24,   25,   42,   58,   91,   75,   90,   74,   167,  183,  166,  182,  184,  185,  155,  139,  168,  169,  154,  138,  107,  123,  106,  122,
      20,   4,    21,   5,    3,    2,    32,   48,   19,   18,   33,   49,   80,   64,   81,   65,   164,  180,  165,  181,  179,  178,  144,  128,  163,  162,  145,  129,  96,   112,  97,   113
  };

  localparam logic [9 : 0] cQAM512_TAB [0 : 511] = '{
    644,  676,  740,  708,  651,  683,  747,  715,  100,  68,   4,    36,   107,  75,   11,   43,   645,  677,  741,  709,  650,  682,  746,  714,  101,  69,   5,    37,   106,  74,   10,   42,
    647,  679,  743,  711,  648,  680,  744,  712,  103,  71,   7,    39,   104,  72,   8,    40,   646,  678,  742,  710,  649,  681,  745,  713,  102,  70,   6,    38,   105,  73,   9,    41,
    611,  579,  515,  547,  387,  419,  483,  451,  131,  163,  227,  195,  355,  323,  259,  291,  610,  578,  514,  546,  386,  418,  482,  450,  130,  162,  226,  194,  354,  322,  258,  290,
    608,  576,  512,  544,  384,  416,  480,  448,  128,  160,  224,  192,  352,  320,  256,  288,  609,  577,  513,  545,  385,  417,  481,  449,  129,  161,  225,  193,  353,  321,  257,  289,
    619,  587,  523,  555,  395,  427,  491,  459,  139,  171,  235,  203,  363,  331,  267,  299,  618,  586,  522,  554,  394,  426,  490,  458,  138,  170,  234,  202,  362,  330,  266,  298,
    616,  584,  520,  552,  392,  424,  488,  456,  136,  168,  232,  200,  360,  328,  264,  296,  617,  585,  521,  553,  393,  425,  489,  457,  137,  169,  233,  201,  361,  329,  265,  297,
    612,  580,  516,  548,  388,  420,  484,  452,  132,  164,  228,  196,  356,  324,  260,  292,  613,  581,  517,  549,  389,  421,  485,  453,  133,  165,  229,  197,  357,  325,  261,  293,
    615,  583,  519,  551,  391,  423,  487,  455,  135,  167,  231,  199,  359,  327,  263,  295,  614,  582,  518,  550,  390,  422,  486,  454,  134,  166,  230,  198,  358,  326,  262,  294,
    659,  691,  755,  723,  652,  684,  748,  716,  115,  83,   19,   51,   108,  76,   12,   44,   658,  690,  754,  722,  653,  685,  749,  717,  114,  82,   18,   50,   109,  77,   13,   45,
    656,  688,  752,  720,  655,  687,  751,  719,  112,  80,   16,   48,   111,  79,   15,   47,   657,  689,  753,  721,  654,  686,  750,  718,  113,  81,   17,   49,   110,  78,   14,   46,
    628,  596,  532,  564,  404,  436,  500,  468,  148,  180,  244,  212,  372,  340,  276,  308,  629,  597,  533,  565,  405,  437,  501,  469,  149,  181,  245,  213,  373,  341,  277,  309,
    631,  599,  535,  567,  407,  439,  503,  471,  151,  183,  247,  215,  375,  343,  279,  311,  630,  598,  534,  566,  406,  438,  502,  470,  150,  182,  246,  214,  374,  342,  278,  310,
    620,  588,  524,  556,  396,  428,  492,  460,  140,  172,  236,  204,  364,  332,  268,  300,  621,  589,  525,  557,  397,  429,  493,  461,  141,  173,  237,  205,  365,  333,  269,  301,
    623,  591,  527,  559,  399,  431,  495,  463,  143,  175,  239,  207,  367,  335,  271,  303,  622,  590,  526,  558,  398,  430,  494,  462,  142,  174,  238,  206,  366,  334,  270,  302,
    627,  595,  531,  563,  403,  435,  499,  467,  147,  179,  243,  211,  371,  339,  275,  307,  626,  594,  530,  562,  402,  434,  498,  466,  146,  178,  242,  210,  370,  338,  274,  306,
    624,  592,  528,  560,  400,  432,  496,  464,  144,  176,  240,  208,  368,  336,  272,  304,  625,  593,  529,  561,  401,  433,  497,  465,  145,  177,  241,  209,  369,  337,  273,  305
  };

  localparam logic [11 : 0] cQAM2048_TAB [0 : 2047] = '{
    2568, 2632, 2760, 2696, 3016, 2952, 2824, 2888, 2583, 2647, 2775, 2711, 3031, 2967, 2839, 2903, 456,  392,  264,  328,  8,    72,   200,  136,  471,  407,  279,  343,  23,   87,   215,  151,  2569, 2633, 2761, 2697, 3017, 2953, 2825, 2889, 2582, 2646, 2774, 2710,	3030,	2966,	2838,	2902,	457,	393,	265,	329,	9,	   73,	  201,	137,	 470,	 406,	278,	 342,	 22,	  86,	  214,	 150,
    2571, 2635, 2763, 2699, 3019, 2955, 2827, 2891, 2580, 2644, 2772, 2708, 3028, 2964, 2836, 2900, 459,  395,  267,  331,  11,   75,   203,  139,  468,  404,  276,  340,  20,   84,   212,  148,  2570, 2634, 2762, 2698, 3018, 2954, 2826, 2890, 2581, 2645, 2773, 2709, 3029,	2965,	2837,	2901,	458,	394,	266,	330,	10,	  74,	  202,	138,	 469,	 405,	277,	 341,	 21,	  85,	  213,	 149,
    2575, 2639, 2767, 2703, 3023, 2959, 2831, 2895, 2576, 2640, 2768, 2704, 3024, 2960, 2832, 2896, 463,  399,  271,  335,  15,   79,   207,  143,  464,  400,  272,  336,  16,   80,   208,  144,  2574, 2638, 2766, 2702, 3022, 2958, 2830, 2894, 2577, 2641, 2769, 2705, 3025,	2961,	2833,	2897,	462,	398,	270,	334,	14,	  78,	  206,	142,	 465,	 401,	273,	 337,	 17,	  81,	  209,	 145,
    2572, 2636, 2764, 2700, 3020, 2956, 2828, 2892, 2579, 2643, 2771, 2707, 3027, 2963, 2835, 2899, 460,  396,  268,  332,  12,   76,   204,  140,  467,  403,  275,  339,  19,   83,   211,  147,  2573, 2637, 2765, 2701, 3021, 2957, 2829, 2893, 2578, 2642, 2770, 2706, 3026,	2962,	2834,	2898,	461,	397,	269,	333,	13,	  77,	  205,	141,	 466,	 402,	274,	 338,	 18,	  82,	  210,	 146,
    2503, 2439, 2311, 2375, 2055, 2119, 2247, 2183, 1543, 1607, 1735, 1671, 1991, 1927, 1799, 1863, 519,  583,  711,  647,  967,  903,  775,  839,  1479, 1415, 1287, 1351, 1031, 1095, 1223, 1159, 2502, 2438, 2310, 2374, 2054, 2118, 2246, 2182, 1542, 1606, 1734,	1670,	1990,	1926,	1798,	1862,	518,	582,	710,	646,	966,	 902,	 774,	838,	1478,	1414,	1286,	1350,	1030,	1094,	1222,	1158,
    2500, 2436, 2308, 2372, 2052, 2116, 2244, 2180, 1540, 1604, 1732, 1668, 1988, 1924, 1796, 1860, 516,  580,  708,  644,  964,  900,  772,  836,  1476, 1412, 1284, 1348, 1028, 1092, 1220, 1156, 2501, 2437, 2309, 2373, 2053, 2117, 2245, 2181, 1541, 1605, 1733,	1669,	1989,	1925,	1797,	1861,	517,	581,	709,	645,	965,	 901,	 773,	837,	1477,	1413,	1285,	1349,	1029,	1093,	1221,	1157,
    2496, 2432, 2304, 2368, 2048, 2112, 2240, 2176, 1536, 1600, 1728, 1664, 1984, 1920, 1792, 1856, 512,  576,  704,  640,  960,  896,  768,  832,  1472, 1408, 1280, 1344, 1024, 1088, 1216, 1152, 2497, 2433, 2305, 2369, 2049, 2113, 2241, 2177, 1537, 1601, 1729,	1665,	1985,	1921,	1793,	1857,	513,	577,	705,	641,	961,	 897,	 769,	833,	1473,	1409,	1281,	1345,	1025,	1089,	1217,	1153,
    2499, 2435, 2307, 2371, 2051, 2115, 2243, 2179, 1539, 1603, 1731, 1667, 1987, 1923, 1795, 1859, 515,  579,  707,  643,  963,  899,  771,  835,  1475, 1411, 1283, 1347, 1027, 1091, 1219, 1155, 2498, 2434, 2306, 2370, 2050, 2114, 2242, 2178, 1538, 1602, 1730,	1666,	1986,	1922,	1794,	1858,	514,	578,	706,	642,	962,	 898,	 770,	834,	1474,	1410,	1282,	1346,	1026,	1090,	1218,	1154,
    2519, 2455, 2327, 2391, 2071, 2135, 2263, 2199, 1559, 1623, 1751, 1687, 2007, 1943, 1815, 1879, 535,  599,  727,  663,  983,  919,  791,  855,  1495, 1431, 1303, 1367, 1047, 1111, 1239, 1175, 2518, 2454, 2326, 2390, 2070, 2134, 2262, 2198, 1558, 1622, 1750,	1686,	2006,	1942,	1814,	1878,	534,	598,	726,	662,	982,	 918,	 790,	854,	1494,	1430,	1302,	1366,	1046,	1110,	1238,	1174,
    2516, 2452, 2324, 2388, 2068, 2132, 2260, 2196, 1556, 1620, 1748, 1684, 2004, 1940, 1812, 1876, 532,  596,  724,  660,  980,  916,  788,  852,  1492, 1428, 1300, 1364, 1044, 1108, 1236, 1172, 2517, 2453, 2325, 2389, 2069, 2133, 2261, 2197, 1557, 1621, 1749,	1685,	2005,	1941,	1813,	1877,	533,	597,	725,	661,	981,	 917,	 789,	853,	1493,	1429,	1301,	1365,	1045,	1109,	1237,	1173,
    2512, 2448, 2320, 2384, 2064, 2128, 2256, 2192, 1552, 1616, 1744, 1680, 2000, 1936, 1808, 1872, 528,  592,  720,  656,  976,  912,  784,  848,  1488, 1424, 1296, 1360, 1040, 1104, 1232, 1168, 2513, 2449, 2321, 2385, 2065, 2129, 2257, 2193, 1553, 1617, 1745,	1681,	2001,	1937,	1809,	1873,	529,	593,	721,	657,	977,	 913,	 785,	849,	1489,	1425,	1297,	1361,	1041,	1105,	1233,	1169,
    2515, 2451, 2323, 2387, 2067, 2131, 2259, 2195, 1555, 1619, 1747, 1683, 2003, 1939, 1811, 1875, 531,  595,  723,  659,  979,  915,  787,  851,  1491, 1427, 1299, 1363, 1043, 1107, 1235, 1171, 2514, 2450, 2322, 2386, 2066, 2130, 2258, 2194, 1554, 1618, 1746,	1682,	2002,	1938,	1810,	1874,	530,	594,	722,	658,	978,	 914,	 786,	850,	1490,	1426,	1298,	1362,	1042,	1106,	1234,	1170,
    2504, 2440, 2312, 2376, 2056, 2120, 2248, 2184, 1544, 1608, 1736, 1672, 1992, 1928, 1800, 1864, 520,  584,  712,  648,  968,  904,  776,  840,  1480, 1416, 1288, 1352, 1032, 1096, 1224, 1160, 2505, 2441, 2313, 2377, 2057, 2121, 2249, 2185, 1545, 1609, 1737,	1673,	1993,	1929,	1801,	1865,	521,	585,	713,	649,	969,	 905,	 777,	841,	1481,	1417,	1289,	1353,	1033,	1097,	1225,	1161,
    2507, 2443, 2315, 2379, 2059, 2123, 2251, 2187, 1547, 1611, 1739, 1675, 1995, 1931, 1803, 1867, 523,  587,  715,  651,  971,  907,  779,  843,  1483, 1419, 1291, 1355, 1035, 1099, 1227, 1163, 2506, 2442, 2314, 2378, 2058, 2122, 2250, 2186, 1546, 1610, 1738,	1674,	1994,	1930,	1802,	1866,	522,	586,	714,	650,	970,	 906,	 778,	842,	1482,	1418,	1290,	1354,	1034,	1098,	1226,	1162,
    2511, 2447, 2319, 2383, 2063, 2127, 2255, 2191, 1551, 1615, 1743, 1679, 1999, 1935, 1807, 1871, 527,  591,  719,  655,  975,  911,  783,  847,  1487, 1423, 1295, 1359, 1039, 1103, 1231, 1167, 2510, 2446, 2318, 2382, 2062, 2126, 2254, 2190, 1550, 1614, 1742,	1678,	1998,	1934,	1806,	1870,	526,	590,	718,	654,	974,	 910,	 782,	846,	1486,	1422,	1294,	1358,	1038,	1102,	1230,	1166,
    2508, 2444, 2316, 2380, 2060, 2124, 2252, 2188, 1548, 1612, 1740, 1676, 1996, 1932, 1804, 1868, 524,  588,  716,  652,  972,  908,  780,  844,  1484, 1420, 1292, 1356, 1036, 1100, 1228, 1164, 2509, 2445, 2317, 2381, 2061, 2125, 2253, 2189, 1549, 1613, 1741,	1677,	1997,	1933,	1805,	1869,	525,	589,	717,	653,	973,	 909,	 781,	845,	1485,	1421,	1293,	1357,	1037,	1101,	1229,	1165,
    2599, 2663, 2791, 2727, 3047, 2983, 2855, 2919, 2584, 2648, 2776, 2712, 3032, 2968, 2840, 2904, 487,  423,  295,  359,  39,   103,  231,  167,  472,  408,  280,  344,  24,   88,   216,  152,  2598, 2662, 2790, 2726, 3046, 2982, 2854, 2918, 2585, 2649, 2777, 2713,	3033,	2969,	2841,	2905,	486,	422,	294,	358,	38,	  102,	 230,	166,	 473,	 409,	281,	 345,	 25,	  89,	  217,	 153,
    2596, 2660, 2788, 2724, 3044, 2980, 2852, 2916, 2587, 2651, 2779, 2715, 3035, 2971, 2843, 2907, 484,  420,  292,  356,  36,   100,  228,  164,  475,  411,  283,  347,  27,   91,   219,  155,  2597, 2661, 2789, 2725, 3045, 2981, 2853, 2917, 2586, 2650, 2778, 2714,	3034,	2970,	2842,	2906,	485,	421,	293,	357,	37,	  101,	 229,	165,	 474,	 410,	282,	 346,	 26,	  90,	  218,	 154,
    2592, 2656, 2784, 2720, 3040, 2976, 2848, 2912, 2591, 2655, 2783, 2719, 3039, 2975, 2847, 2911, 480,  416,  288,  352,  32,   96,   224,  160,  479,  415,  287,  351,  31,   95,   223,  159,  2593, 2657, 2785, 2721, 3041, 2977, 2849, 2913, 2590, 2654, 2782, 2718, 3038,	2974,	2846,	2910,	481,	417,	289,	353,	33,	  97,	  225,	161,	 478,	 414,	286,	 350,	 30,	  94,	  222,	 158,
    2595, 2659, 2787, 2723, 3043, 2979, 2851, 2915, 2588, 2652, 2780, 2716, 3036, 2972, 2844, 2908, 483,  419,  291,  355,  35,   99,   227,  163,  476,  412,  284,  348,  28,   92,   220,  156,  2594, 2658, 2786, 2722, 3042, 2978, 2850, 2914, 2589, 2653, 2781, 2717, 3037,	2973,	2845,	2909,	482,	418,	290,	354,	34,	  98,	  226,	162,	 477,	 413,	285,	 349,	 29,	  93,	  221,	 157,
    2536, 2472, 2344, 2408, 2088, 2152, 2280, 2216, 1576, 1640, 1768, 1704, 2024, 1960, 1832, 1896, 552,  616,  744,  680,  1000, 936,  808,  872,  1512, 1448, 1320, 1384, 1064, 1128, 1256, 1192, 2537, 2473, 2345, 2409, 2089, 2153, 2281, 2217, 1577, 1641, 1769,	1705,	2025,	1961,	1833,	1897,	553,	617,	745,	681,	1001,	937,	 809,	873,	1513,	1449,	1321,	1385,	1065,	1129,	1257,	1193,
    2539, 2475, 2347, 2411, 2091, 2155, 2283, 2219, 1579, 1643, 1771, 1707, 2027, 1963, 1835, 1899, 555,  619,  747,  683,  1003, 939,  811,  875,  1515, 1451, 1323, 1387, 1067, 1131, 1259, 1195, 2538, 2474, 2346, 2410, 2090, 2154, 2282, 2218, 1578, 1642, 1770,	1706,	2026,	1962,	1834,	1898,	554,	618,	746,	682,	1002,	938,	 810,	874,	1514,	1450,	1322,	1386,	1066,	1130,	1258,	1194,
    2543, 2479, 2351, 2415, 2095, 2159, 2287, 2223, 1583, 1647, 1775, 1711, 2031, 1967, 1839, 1903, 559,  623,  751,  687,  1007, 943,  815,  879,  1519, 1455, 1327, 1391, 1071, 1135, 1263, 1199, 2542, 2478, 2350, 2414, 2094, 2158, 2286, 2222, 1582, 1646, 1774,	1710,	2030,	1966,	1838,	1902,	558,	622,	750,	686,	1006,	942,	 814,	878,	1518,	1454,	1326,	1390,	1070,	1134,	1262,	1198,
    2540, 2476, 2348, 2412, 2092, 2156, 2284, 2220, 1580, 1644, 1772, 1708, 2028, 1964, 1836, 1900, 556,  620,  748,  684,  1004, 940,  812,  876,  1516, 1452, 1324, 1388, 1068, 1132, 1260, 1196, 2541, 2477, 2349, 2413, 2093, 2157, 2285, 2221, 1581, 1645, 1773,	1709,	2029,	1965,	1837,	1901,	557,	621,	749,	685,	1005,	941,	 813,	877,	1517,	1453,	1325,	1389,	1069,	1133,	1261,	1197,
    2520, 2456, 2328, 2392, 2072, 2136, 2264, 2200, 1560, 1624, 1752, 1688, 2008, 1944, 1816, 1880, 536,  600,  728,  664,  984,  920,  792,  856,  1496, 1432, 1304, 1368, 1048, 1112, 1240, 1176, 2521, 2457, 2329, 2393, 2073, 2137, 2265, 2201, 1561, 1625, 1753,	1689,	2009,	1945,	1817,	1881,	537,	601,	729,	665,	985,	 921,	 793,	857,	1497,	1433,	1305,	1369,	1049,	1113,	1241,	1177,
    2523, 2459, 2331, 2395, 2075, 2139, 2267, 2203, 1563, 1627, 1755, 1691, 2011, 1947, 1819, 1883, 539,  603,  731,  667,  987,  923,  795,  859,  1499, 1435, 1307, 1371, 1051, 1115, 1243, 1179, 2522, 2458, 2330, 2394, 2074, 2138, 2266, 2202, 1562, 1626, 1754,	1690,	2010,	1946,	1818,	1882,	538,	602,	730,	666,	986,	 922,	 794,	858,	1498,	1434,	1306,	1370,	1050,	1114,	1242,	1178,
    2527, 2463, 2335, 2399, 2079, 2143, 2271, 2207, 1567, 1631, 1759, 1695, 2015, 1951, 1823, 1887, 543,  607,  735,  671,  991,  927,  799,  863,  1503, 1439, 1311, 1375, 1055, 1119, 1247, 1183, 2526, 2462, 2334, 2398, 2078, 2142, 2270, 2206, 1566, 1630, 1758,	1694,	2014,	1950,	1822,	1886,	542,	606,	734,	670,	990,	 926,	 798,	862,	1502,	1438,	1310,	1374,	1054,	1118,	1246,	1182,
    2524, 2460, 2332, 2396, 2076, 2140, 2268, 2204, 1564, 1628, 1756, 1692, 2012, 1948, 1820, 1884, 540,  604,  732,  668,  988,  924,  796,  860,  1500, 1436, 1308, 1372, 1052, 1116, 1244, 1180, 2525, 2461, 2333, 2397, 2077, 2141, 2269, 2205, 1565, 1629, 1757,	1693,	2013,	1949,	1821,	1885,	541,	605,	733,	669,	989,	 925,	 797,	861,	1501,	1437,	1309,	1373,	1053,	1117,	1245,	1181,
    2535, 2471, 2343, 2407, 2087, 2151, 2279, 2215, 1575, 1639, 1767, 1703, 2023, 1959, 1831, 1895, 551,  615,  743,  679,  999,  935,  807,  871,  1511, 1447, 1319, 1383, 1063, 1127, 1255, 1191, 2534, 2470, 2342, 2406, 2086, 2150, 2278, 2214, 1574, 1638, 1766,	1702,	2022,	1958,	1830,	1894,	550,	614,	742,	678,	998,	 934,	 806,	870,	1510,	1446,	1318,	1382,	1062,	1126,	1254,	1190,
    2532, 2468, 2340, 2404, 2084, 2148, 2276, 2212, 1572, 1636, 1764, 1700, 2020, 1956, 1828, 1892, 548,  612,  740,  676,  996,  932,  804,  868,  1508, 1444, 1316, 1380, 1060, 1124, 1252, 1188, 2533, 2469, 2341, 2405, 2085, 2149, 2277, 2213, 1573, 1637, 1765,	1701,	2021,	1957,	1829,	1893,	549,	613,	741,	677,	997,	 933,	 805,	869,	1509,	1445,	1317,	1381,	1061,	1125,	1253,	1189,
    2528, 2464, 2336, 2400, 2080, 2144, 2272, 2208, 1568, 1632, 1760, 1696, 2016, 1952, 1824, 1888, 544,  608,  736,  672,  992,  928,  800,  864,  1504, 1440, 1312, 1376, 1056, 1120, 1248, 1184, 2529, 2465, 2337, 2401, 2081, 2145, 2273, 2209, 1569, 1633, 1761,	1697,	2017,	1953,	1825,	1889,	545,	609,	737,	673,	993,	 929,	 801,	865,	1505,	1441,	1313,	1377,	1057,	1121,	1249,	1185,
    2531, 2467, 2339, 2403, 2083, 2147, 2275, 2211, 1571, 1635, 1763, 1699, 2019, 1955, 1827, 1891, 547,  611,  739,  675,  995,  931,  803,  867,  1507, 1443, 1315, 1379, 1059, 1123, 1251, 1187, 2530, 2466, 2338, 2402, 2082, 2146, 2274, 2210, 1570, 1634, 1762,	1698,	2018,	1954,	1826,	1890,	546,	610,	738,	674,	994,	 930,	 802,	866,	1506,	1442,	1314,	1378,	1058,	1122,	1250,	1186
  };

  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------

  logic         sop,  tsop ;
  logic         val,  tval ;
  logic         eop,  teop ;
  logic [3 : 0] qam,  tqam ;

  logic         qam2_im,    qam2_re,      tqam2_im,    tqam2_re;
  logic         qam4_im,    qam4_re,      tqam4_im,    tqam4_re;

  logic [1 : 0] qam8_im,    qam8_re,      tqam8_im,    tqam8_re;
  logic [1 : 0] qam16_im,   qam16_re,     tqam16_im,   tqam16_re;

  logic [2 : 0] qam32_im,   qam32_re,     tqam32_im,   tqam32_re;
  logic [2 : 0] qam64_im,   qam64_re,     tqam64_im,   tqam64_re;

  logic [3 : 0] qam128_im,  qam128_re,    tqam128_im,  tqam128_re;
  logic [3 : 0] qam256_im,  qam256_re,    tqam256_im,  tqam256_re;

  logic [4 : 0] qam512_im,  qam512_re,    tqam512_im,  tqam512_re;
  logic [4 : 0] qam1024_im, qam1024_re,   tqam1024_im, tqam1024_re;

  logic [5 : 0] qam2048_im, qam2048_re,   tqam2048_im, tqam2048_re;
  logic [5 : 0] qam4096_im, qam4096_re,   tqam4096_im, tqam4096_re;

  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------
  // synthesis translate_off
  initial begin
    oval    <= '0;
    oqam    <= '0;
    odat_re <= '0;
    odat_im <= '0;
  end
  // synthesis translate_on
  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------

  always_ff @(posedge iclk or posedge ireset) begin
    if (ireset) begin
      val <= 1'b0;
    end
    else if (iclkena) begin
      val <= ival;
    end
  end

  always_ff @(posedge iclk) begin
    if (iclkena) begin
      sop <= isop;
      eop <= ieop;
      qam <= iqam;
      //
      // BPSK mapper
      //      0 = -1 - 1i
      //      1 =  1 + 1i
      qam2_im                    <= idat[0];
      qam2_re                    <= idat[0];
      //
      // QPSK mapper
      //     00 = -1 - 1i
      //     01 = -1 + 1i
      //     10 =  1 - 1i
      //     11 =  1 + 1i
      qam4_im                    <= idat[1];
      qam4_re                    <= idat[0];

      {qam8_im,  qam8_re}         <= cQAM8_TAB[idat[2:0]];

      qam16_im                   <= gray2bin(idat[3:2], 2);
      qam16_re                   <= gray2bin(idat[1:0], 2);

      if (pBMAX > 4) begin
        {qam32_im, qam32_re}      <= cQAM32_TAB[idat[4:0]];

         qam64_im                 <= gray2bin(idat[5:3], 3);
         qam64_re                 <= gray2bin(idat[2:0], 3);
      end
      //
      if (pBMAX > 6) begin
        {qam128_im, qam128_re}    <= cQAM128_TAB[idat[6:0]];

         qam256_im                <= gray2bin(idat[7:4], 4);
         qam256_re                <= gray2bin(idat[3:0], 4);
      end
      //
      if (pBMAX > 8) begin
        {qam512_im, qam512_re}    <= cQAM512_TAB[idat[8:0]];

         qam1024_im               <= gray2bin(idat[9:5], 5);
         qam1024_re               <= gray2bin(idat[4:0], 5);
      end
      //
      if (pBMAX > 10) begin
        {qam2048_im, qam2048_re}  <= cQAM2048_TAB[idat[10:0]];

         qam4096_im               <= gray2bin(idat[11:6], 6);
         qam4096_re               <= gray2bin(idat[ 5:0], 6);
      end
    end
  end

  //------------------------------------------------------------------------------------------------------
  // internal pipeline
  //------------------------------------------------------------------------------------------------------

  always_ff @(posedge iclk or posedge ireset) begin
    if (ireset) begin
      tval <= 1'b0;
    end
    else if (iclkena) begin
      tval <= val;
    end
  end

  always_ff @(posedge iclk) begin
    if (iclkena) begin
      tsop <= sop;
      teop <= eop;
      tqam <= qam;
      //
      {tqam2_im,     tqam2_re}    <= {qam2_im,    qam2_re};
      {tqam4_im,     tqam4_re}    <= {qam4_im,    qam4_re};
      {tqam8_im,     tqam8_re}    <= {qam8_im,    qam8_re};
      {tqam16_im,    tqam16_re}   <= {qam16_im,   qam16_re};
      {tqam32_im,    tqam32_re}   <= {qam32_im,   qam32_re};
      {tqam64_im,    tqam64_re}   <= {qam64_im,   qam64_re};
      {tqam128_im,   tqam128_re}  <= {qam128_im,  qam128_re};
      {tqam256_im,   tqam256_re}  <= {qam256_im,  qam256_re};
      {tqam512_im,   tqam512_re}  <= {qam512_im,  qam512_re};
      {tqam1024_im,  tqam1024_re} <= {qam1024_im, qam1024_re};
      {tqam2048_im,  tqam2048_re} <= {qam2048_im, qam2048_re};
      {tqam4096_im,  tqam4096_re} <= {qam4096_im, qam4096_re};
    end
  end

  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------

  always_ff @(posedge iclk or posedge ireset) begin
    if (ireset) begin
      oval <= 1'b0;
    end
    else if (iclkena) begin
      oval <= tval;
    end
  end

  always_ff @(posedge iclk) begin
    if (iclkena) begin
      osop    <= tsop;
      oeop    <= teop;
      oqam    <= tqam;
      //
      if (tval) begin
        odat_re[pBMAX/2-1 : 1] <= '0; odat_re[0] <= tqam4_re;
        odat_im[pBMAX/2-1 : 1] <= '0; odat_im[0] <= tqam4_im;
        case (tqam)
          4'd1    : begin
            odat_re[0] <= tqam2_re;
            odat_im[0] <= tqam2_im;
          end
          4'd2    : begin
            odat_re[0] <= tqam4_re;
            odat_im[0] <= tqam4_im;
          end
          //
          //
          //
          4'd3    : begin
            odat_re[1 : 0] <= tqam8_re;
            odat_im[1 : 0] <= tqam8_im;
          end
          4'd4    : begin
            odat_re[1 : 0] <= tqam16_re;
            odat_im[1 : 0] <= tqam16_im;
          end
          //
          //
          //
          4'd5    : begin
            if (pBMAX > 4) begin
              odat_re[2 : 0] <= tqam32_re;
              odat_im[2 : 0] <= tqam32_im;
            end
          end
          4'd6    : begin
            if (pBMAX > 4) begin
              odat_re[2 : 0] <= tqam64_re;
              odat_im[2 : 0] <= tqam64_im;
            end
          end
          //
          //
          //
          4'd7    : begin
            if (pBMAX > 6) begin
              odat_re[3 : 0] <= tqam128_re;
              odat_im[3 : 0] <= tqam128_im;
            end
          end
          4'd8    : begin
            if (pBMAX > 6) begin
              odat_re[3 : 0] <= tqam256_re;
              odat_im[3 : 0] <= tqam256_im;
            end
          end
          //
          //
          //
          4'd9    : begin
            if (pBMAX > 8) begin
              odat_re[4 : 0] <= tqam512_re;
              odat_im[4 : 0] <= tqam512_im;
            end
          end
          //
          4'd10   : begin
            if (pBMAX > 8) begin
              odat_re[4 : 0] <= tqam1024_re;
              odat_im[4 : 0] <= tqam1024_im;
            end
          end
          //
          //
          //
          4'd11    : begin
            if (pBMAX > 10) begin
              odat_re[5 : 0] <= tqam2048_re;
              odat_im[5 : 0] <= tqam2048_im;
            end
          end
          //
          4'd12   : begin
            if (pBMAX > 10) begin
              odat_re[5 : 0] <= tqam4096_re;
              odat_im[5 : 0] <= tqam4096_im;
            end
          end
          //
          default : begin end
        endcase
      end // tval
    end // iclkena
  end // iclk

  //------------------------------------------------------------------------------------------------------
  //
  //------------------------------------------------------------------------------------------------------

  function automatic logic [cDAT_W-1 : 0] gray2bin (input logic [cDAT_W-1 : 0] gray, input int size);
    bit [cDAT_W-1 : 0] gray_mask;
    bit [cDAT_W-1 : 0] gray_masked;
  begin
    gray_mask   = {cDAT_W{1'b1}} >> (cDAT_W - size);
    gray_masked = gray & gray_mask;
    //
    gray2bin    = '0;
    for (int i = 0; i < cDAT_W; i++) begin
      gray2bin[i] = ^(gray_masked >> i);
    end
  end
  endfunction

endmodule
